#include <atomic>
#include <chrono>
#include <cstring>
#include <fstream>
#include <future>
#include <thread>
#include <vector>
#include <filesystem>
#include "gtest/gtest.h"
#define private public
#include "async_logger.h"
#include "async_fsync.h"
#include "file_output_strategy.h"
#include "console_output_strategy.h"
#undef private

#define UNUSED(x) (void)(x)
namespace Base {
namespace SystemLog {
using namespace std::chrono_literals;

namespace {
constexpr const char* TEST_LOG_DIR = "out/tests/logs";
const char TEST_CHAR = 't';
constexpr int TEST_MESSAGES_COUNT = 100; // 单元测试用较小数量
constexpr size_t TEST_MESSAGE_SIZE = 64;
constexpr size_t TEST_MB = 1024 * 1024;
constexpr size_t TEST_BUFFER_SIZE = 1 * TEST_MB;
constexpr uint32_t TEST_FLUSH_INTERVAL_MS = 50;
constexpr size_t TEST_SOFT_FLUSH_THRESHOLD = TEST_BUFFER_SIZE / 4;
constexpr size_t TEST_HARD_FLUSH_THRESHOLD = TEST_BUFFER_SIZE / 2;

class TestOutput {
public:
    ErrCode operator()(const char* data, size_t len) {
        std::lock_guard<std::mutex> lock(mutex_);
        output_.append(data, len);
        totalBytes_ += len;
        return ERR_OK;
    }

    const std::string &GetOutput() {
        std::lock_guard<std::mutex> lock(mutex_);
        return output_;
    }

    size_t GetTotalBytes() {
        std::lock_guard<std::mutex> lock(mutex_);
        return totalBytes_;
    }

    void Clear() {
        std::lock_guard<std::mutex> lock(mutex_);
        output_.clear();
        totalBytes_ = 0;
    }

private:
    std::string output_;
    size_t totalBytes_ = 0;
    std::mutex mutex_;
};

} // namespace

class AsyncFsyncTest : public testing::Test {
protected:
    static void SetUpTestCase(void);
    static void TearDownTestCase(void);
    void SetUp();
    void TearDown();

    std::unique_ptr<AsyncLogger<TEST_BUFFER_SIZE>> logger_;
    std::shared_ptr<TestOutput> testOutput_;
    std::string testDir_;
};

void AsyncFsyncTest::SetUpTestCase(void)
{}

void AsyncFsyncTest::TearDownTestCase(void)
{}

void AsyncFsyncTest::SetUp()
{
    // 创建测试目录
    testDir_ = std::string(TEST_LOG_DIR) + "/test_async_fsync_unit_logs";
    std::filesystem::create_directories(testDir_);

    // 创建日志器和测试输出
    logger_ = std::make_unique<AsyncLogger<TEST_BUFFER_SIZE>>();
    testOutput_ = std::make_shared<TestOutput>();
    
    // 创建一个自定义输出策略来替代SetOutputFunction
    class TestOutputStrategy : public IOutputStrategy {
        std::shared_ptr<TestOutput> testOutput_;
    public:
        TestOutputStrategy(std::shared_ptr<TestOutput> output) : testOutput_(std::move(output)) {}
        ErrCode Write(const char* data, size_t len) override {
            return (*testOutput_)(data, len);
        }
        ErrCode Flush() override { return ERR_OK; }
        ErrCode Close() override { return ERR_OK; }
        std::string GetName() const override { return "TestOutputStrategy"; }
    };
    
    logger_->AddOutputStrategy(std::make_unique<TestOutputStrategy>(testOutput_));
    logger_->SetFlushThreshold(TEST_SOFT_FLUSH_THRESHOLD, TEST_HARD_FLUSH_THRESHOLD);
    logger_->SetFlushInterval(TEST_FLUSH_INTERVAL_MS);
}

void AsyncFsyncTest::TearDown()
{
    if (logger_) {
        logger_->Stop();
        logger_.reset();
    }
    
    // 清理测试目录
    try {
        if (std::filesystem::exists(testDir_)) {
            // std::filesystem::remove_all(testDir_);
        }
    } catch (const std::filesystem::filesystem_error &ex) {
        GTEST_LOG_(ERROR) << "Failed to remove test directory: " << ex.what() << std::endl;
    }
}

/**
 * @tc.name: AsyncFsyncTest_001
 * @tc.desc: verify AsyncFsync basic functionality
 * @tc.type: FUNC
 */
TEST_F(AsyncFsyncTest, AsyncFsyncTest_001)
{
    auto& asyncFsync = AsyncFsync::GetInstance();

    // 创建测试文件
    std::string testFile = testDir_ + "/basic_test.log";
    int fd = open(testFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
    ASSERT_GE(fd, 0);

    // 写入数据
    const char* testData = "AsyncFsync basic test data\n";
    ssize_t written = write(fd, testData, strlen(testData));
    EXPECT_EQ(written, static_cast<ssize_t>(strlen(testData)));

    // 添加到AsyncFsync管理
    asyncFsync.AddFile(fd);
    EXPECT_EQ(asyncFsync.GetFileCount(), static_cast<size_t>(1));

    // 请求立即同步
    asyncFsync.RequestImmediateSync(fd);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    // 移除文件
    asyncFsync.RemoveFile(fd);
    EXPECT_EQ(asyncFsync.GetFileCount(), static_cast<size_t>(0));

    close(fd);

    // 验证文件内容
    std::ifstream file(testFile);
    ASSERT_TRUE(file.is_open());
    std::string content((std::istreambuf_iterator<char>(file)),
                        std::istreambuf_iterator<char>());
    EXPECT_EQ(content, testData);
}

/**
 * @tc.name: AsyncFsyncTest_002
 * @tc.desc: verify AsyncFsync timed sync functionality
 * @tc.type: FUNC
 */
TEST_F(AsyncFsyncTest, AsyncFsyncTest_002)
{
    auto& asyncFsync = AsyncFsync::GetInstance();
    asyncFsync.SetSyncInterval(200); // 短间隔用于测试

    std::string testFile = testDir_ + "/timed_test.log";
    int fd = open(testFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
    ASSERT_GE(fd, 0);

    asyncFsync.AddFile(fd);

    // 写入数据
    const char* testData = "Timed sync test data\n";
    ssize_t result = write(fd, testData, strlen(testData));
    ASSERT_GT(result, 0);

    // 等待自动同步
    std::this_thread::sleep_for(std::chrono::milliseconds(300));

    asyncFsync.RemoveFile(fd);
    close(fd);

    // 验证文件内容
    std::ifstream file(testFile);
    ASSERT_TRUE(file.is_open());
    std::string content((std::istreambuf_iterator<char>(file)),
                        std::istreambuf_iterator<char>());
    EXPECT_EQ(content, testData);
}

/**
 * @tc.name: AsyncFsyncTest_003
 * @tc.desc: verify AsyncFsync configuration
 * @tc.type: FUNC
 */
TEST_F(AsyncFsyncTest, AsyncFsyncTest_003)
{
    auto& asyncFsync = AsyncFsync::GetInstance();
    
    // 测试不同的同步间隔配置
    std::vector<uint32_t> intervals = {100, 500, 1000};
    
    for (uint32_t interval : intervals) {
        asyncFsync.SetSyncInterval(interval);
        
        std::string testFile = testDir_ + "/config_" + std::to_string(interval) + ".log";
        int fd = open(testFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
        ASSERT_GE(fd, 0);
        
        asyncFsync.AddFile(fd);
        
        // 写入数据
        const char* testData = "Config test data\n";
        ssize_t written = write(fd, testData, strlen(testData));
        EXPECT_GT(written, 0);
        
        // 验证文件被添加
        EXPECT_GT(asyncFsync.GetFileCount(), static_cast<size_t>(0));
        
        asyncFsync.RemoveFile(fd);
        close(fd);
    }
}

} // namespace SystemLog
} // namespace Base